package service

import (
	"bytes"
	"context"
	"fmt"
	"image-sever-grpc/oss-server/config"
	ossgrpc "image-sever-grpc/oss-server/proto"
	"log"
	"strings"
	"sync"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/sts"
	ossSDK "github.com/aliyun/aliyun-oss-go-sdk/oss" // 阿里云OSS SDK包，别名ossSDK
)

// OSSService 实现gRPC服务
type OSSService struct {
	ossgrpc.UnimplementedOSSServiceServer                // 使用proto包别名ossgrpc
	bucket                                *ossSDK.Bucket // 使用SDK包别名ossSDK
	bucketOnce                            sync.Once
	bucketInitError                       error
}

var globalOSSService *OSSService

func GetOSSService() (*OSSService, error) {
	if globalOSSService == nil {
		globalOSSService = &OSSService{}
		globalOSSService.bucketOnce.Do(func() {
			client, err := config.NewOSSClient()
			if err != nil {
				globalOSSService.bucketInitError = fmt.Errorf("初始化OSS客户端失败: %w", err)
				return
			}
			globalOSSService.bucket, globalOSSService.bucketInitError = client.Bucket(config.Aliyun.Bucket)
			if globalOSSService.bucketInitError != nil {
				globalOSSService.bucketInitError = fmt.Errorf("获取存储桶失败: %w", globalOSSService.bucketInitError)
			}
		})
	}
	return globalOSSService, globalOSSService.bucketInitError
}

// UploadBatchToOSS 基于阿里云OSS SDK的批量上传实现
func (s *OSSService) UploadBatchToOSS(ctx context.Context, req *ossgrpc.UploadBatchToOSSRequest) (*ossgrpc.UploadBatchToOSSResponse, error) {
	resp := &ossgrpc.UploadBatchToOSSResponse{
		Results: make([]*ossgrpc.UploadToOSSResponse, len(req.Files)),
	}

	// 初始化所有结果为“未处理”
	for i := range resp.Results {
		resp.Results[i] = &ossgrpc.UploadToOSSResponse{
			Error: &ossgrpc.ErrorResponse{
				Success:  false,
				ErrorMsg: "未处理",
			},
		}
	}
	// 检查文件数量
	if len(req.Files) == 0 {
		log.Println("批量上传：未收到任何文件")
		return resp, nil
	}
	log.Printf("批量上传：开始处理 %d 个文件", len(req.Files))

	// 检查OSS客户端是否初始化成功
	if s.bucket == nil {
		errMsg := "OSS客户端未初始化"
		if s.bucketInitError != nil {
			errMsg = s.bucketInitError.Error()
		}
		log.Printf("批量上传失败：%s", errMsg)
		for i := range resp.Results {
			resp.Results[i].Error.ErrorMsg = errMsg
		}
		return resp, nil
	}
	// 并发控制：最多10个同时上传
	sem := make(chan struct{}, 10)
	var wg sync.WaitGroup
	errChan := make(chan error, 1) // 用于传递全局错误（如panic）

	for i, fileReq := range req.Files {
		// 提前校验参数，避免无效goroutine
		if fileReq.ObjectKey == "" {
			resp.Results[i].Error.ErrorMsg = "object_key不能为空"
			log.Printf("文件 %d 校验失败：object_key为空", i)
			continue
		}
		if len(fileReq.Content) == 0 {
			resp.Results[i].Error.ErrorMsg = "文件内容为空"
			log.Printf("文件 %d（%s）校验失败：内容为空", i, fileReq.ObjectKey)
			continue
		}

		wg.Add(1)
		// 启动goroutine处理上传，在内部获取信号量（避免阻塞主循环）
		go func(idx int, req *ossgrpc.UploadToOSSRequest) {
			defer wg.Done()
			sem <- struct{}{}        // 获取信号量
			defer func() { <-sem }() // 释放信号量

			// 捕获panic，避免单个文件上传失败导致整个服务崩溃
			defer func() {
				if r := recover(); r != nil {
					err := fmt.Errorf("文件 %s 上传 panic: %v", req.ObjectKey, r)
					resp.Results[idx].Error.ErrorMsg = err.Error()
					select {
					case errChan <- err: // 发送错误到全局通道
					default:
					}
					log.Println(err)
				}
			}()

			// 检查是否已有全局错误，直接返回
			select {
			case <-errChan:
				resp.Results[idx].Error.ErrorMsg = "批量上传被全局错误中断"
				return
			default:
			}

			// 执行OSS上传
			log.Printf("文件 %d（%s）开始上传，大小：%d bytes", idx, req.ObjectKey, len(req.Content))
			reader := bytes.NewReader(req.Content)
			err := s.bucket.PutObject(req.ObjectKey, reader, nil)
			if err != nil {
				resp.Results[idx].Error.ErrorMsg = fmt.Sprintf("上传失败: %v", err)
				log.Printf("文件 %d（%s）上传失败：%v", idx, req.ObjectKey, err)
				return
			}

			// 上传成功
			resp.Results[idx].Error = &ossgrpc.ErrorResponse{
				Success: true,
			}
			log.Printf("文件 %d（%s）上传成功", idx, req.ObjectKey)
		}(i, fileReq)
	}

	// 等待所有上传完成后关闭错误通道
	go func() {
		wg.Wait()
		close(errChan)
		log.Printf("批量上传：所有文件处理完成")
	}()

	// 处理全局错误（如panic）
	if err := <-errChan; err != nil {
		log.Printf("批量上传发生全局错误：%v", err)
		// 仅更新未成功的文件状态
		for i := range resp.Results {
			if !resp.Results[i].Error.Success && resp.Results[i].Error.ErrorMsg == "未处理" {
				resp.Results[i].Error.ErrorMsg = fmt.Sprintf("批量上传异常: %v", err)
			}
		}
	}

	return resp, nil
}

// 上传文件
func (s *OSSService) UploadToOSS(ctx context.Context, req *ossgrpc.UploadToOSSRequest) (*ossgrpc.UploadToOSSResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.UploadToOSSResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	err := uploadObject(s.bucket, req.ObjectKey, req.Content)
	if err != nil {
		return &ossgrpc.UploadToOSSResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.UploadToOSSResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 删除单个文件
func (s *OSSService) DeleteFromOSS(ctx context.Context, req *ossgrpc.DeleteFromOSSRequest) (*ossgrpc.DeleteFromOSSResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.DeleteFromOSSResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	err := deleteObject(s.bucket, req.ObjectKey)
	if err != nil {
		return &ossgrpc.DeleteFromOSSResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.DeleteFromOSSResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 生成签名URL
func (s *OSSService) GenerateSignedURL(ctx context.Context, req *ossgrpc.GenerateSignedURLRequest) (*ossgrpc.GenerateSignedURLResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.GenerateSignedURLResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	signedURL, err := generateSignedURL(s.bucket, req.ObjectKey, req.ExpireSeconds)
	if err != nil {
		return &ossgrpc.GenerateSignedURLResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.GenerateSignedURLResponse{
		Error:     &ossgrpc.ErrorResponse{Success: true},
		SignedUrl: signedURL,
	}, nil
}

// 重命名文件夹（批量移动）
func (s *OSSService) RenameOSSFolder(ctx context.Context, req *ossgrpc.RenameOSSFolderRequest) (*ossgrpc.RenameOSSFolderResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.RenameOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	oldFolder := normalizeFolderPath(req.OldFolder)
	newFolder := normalizeFolderPath(req.NewFolder)
	err := RenameOSSFolder(s.bucket, oldFolder, newFolder)
	if err != nil {
		return &ossgrpc.RenameOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.RenameOSSFolderResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 删除文件夹及内容
func (s *OSSService) DeleteOSSFolder(ctx context.Context, req *ossgrpc.DeleteOSSFolderRequest) (*ossgrpc.DeleteOSSFolderResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.DeleteOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	folderPath := normalizeFolderPath(req.FolderPath)
	err := DeleteOSSFolder(s.bucket, folderPath)
	if err != nil {
		return &ossgrpc.DeleteOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.DeleteOSSFolderResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 创建文件夹
func (s *OSSService) CreateOSSFolder(ctx context.Context, req *ossgrpc.CreateOSSFolderRequest) (*ossgrpc.CreateOSSFolderResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.CreateOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	folderPath := normalizeFolderPath(req.FolderPath)
	err := CreateOSSFolder(s.bucket, folderPath)
	if err != nil {
		return &ossgrpc.CreateOSSFolderResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.CreateOSSFolderResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 检查路径存在性
func (s *OSSService) CheckOSSPathExists(ctx context.Context, req *ossgrpc.CheckOSSPathExistsRequest) (*ossgrpc.CheckOSSPathExistsResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.CheckOSSPathExistsResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	exists, err := CheckOSSPathExists(s.bucket, req.Path)
	if err != nil {
		return &ossgrpc.CheckOSSPathExistsResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.CheckOSSPathExistsResponse{
		Error:  &ossgrpc.ErrorResponse{Success: true},
		Exists: exists,
	}, nil
}

// 设置文件夹ACL
func (s *OSSService) SetOSSFolderACL(ctx context.Context, req *ossgrpc.SetOSSFolderACLRequest) (*ossgrpc.SetOSSFolderACLResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.SetOSSFolderACLResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	folderPath := normalizeFolderPath(req.FolderPath)
	err := SetOSSFolderACL(s.bucket, folderPath, req.IsPublic)
	if err != nil {
		return &ossgrpc.SetOSSFolderACLResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.SetOSSFolderACLResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 批量删除对象
func (s *OSSService) DeleteObjects(ctx context.Context, req *ossgrpc.DeleteObjectsRequest) (*ossgrpc.DeleteObjectsResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.DeleteObjectsResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	err := DeleteObjects(s.bucket, req.Keys)
	if err != nil {
		return &ossgrpc.DeleteObjectsResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.DeleteObjectsResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 重命名单个文件
func (s *OSSService) RenameOSSObject(ctx context.Context, req *ossgrpc.RenameOSSObjectRequest) (*ossgrpc.RenameOSSObjectResponse, error) {
	if s.bucket == nil {
		return &ossgrpc.RenameOSSObjectResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: s.bucketInitError.Error(), Success: false},
		}, nil
	}
	err := RenameOSSObject(s.bucket, req.OldKey, req.NewKey)
	if err != nil {
		return &ossgrpc.RenameOSSObjectResponse{
			Error: &ossgrpc.ErrorResponse{ErrorMsg: err.Error(), Success: false},
		}, nil
	}
	return &ossgrpc.RenameOSSObjectResponse{
		Error: &ossgrpc.ErrorResponse{Success: true},
	}, nil
}

// 清理文件名
func (s *OSSService) SanitizeFileName(ctx context.Context, req *ossgrpc.SanitizeFileNameRequest) (*ossgrpc.SanitizeFileNameResponse, error) {
	sanitized := SanitizeFileName(req.Name)
	return &ossgrpc.SanitizeFileNameResponse{
		Error:         &ossgrpc.ErrorResponse{Success: true},
		SanitizedName: sanitized,
	}, nil
}

// --------------------- 工具函数 ---------------------

func uploadObject(bucket *ossSDK.Bucket, objectKey string, content []byte) error {
	if objectKey == "" {
		return fmt.Errorf("OSS存储路径不能为空")
	}
	if len(content) == 0 {
		return fmt.Errorf("文件内容不能为空")
	}
	return bucket.PutObject(objectKey, bytes.NewReader(content))
}

func deleteObject(bucket *ossSDK.Bucket, objectKey string) error {
	if objectKey == "" {
		return fmt.Errorf("OSS存储路径不能为空")
	}
	exists, err := bucket.IsObjectExist(objectKey)
	if err != nil {
		return fmt.Errorf("检查对象存在性失败: %w", err)
	}
	if !exists {
		return fmt.Errorf("对象不存在: %s", objectKey)
	}
	return bucket.DeleteObject(objectKey)
}

func generateSignedURL(bucket *ossSDK.Bucket, objectKey string, expireSeconds int64) (string, error) {
	if objectKey == "" {
		return "", fmt.Errorf("OSS存储路径不能为空")
	}
	if expireSeconds <= 0 {
		expireSeconds = 3600
	}
	exists, err := bucket.IsObjectExist(objectKey)
	if err != nil {
		return "", fmt.Errorf("检查对象存在性失败: %w", err)
	}
	if !exists {
		return "", fmt.Errorf("对象不存在: %s", objectKey)
	}
	return bucket.SignURL(objectKey, "GET", expireSeconds)
}

func RenameOSSFolder(bucket *ossSDK.Bucket, oldFolder, newFolder string) error {
	if oldFolder == "" || newFolder == "" {
		return fmt.Errorf("源文件夹和目标文件夹路径不能为空")
	}
	oldFolder = normalizeFolderPath(oldFolder)
	newFolder = normalizeFolderPath(newFolder)

	var copiedObjects []string
	defer func() {
		if len(copiedObjects) > 0 {
			_ = deleteObjects(bucket, copiedObjects)
		}
	}()

	marker := ""
	for {
		resp, err := bucket.ListObjects(
			ossSDK.Prefix(oldFolder),
			ossSDK.Marker(marker),
			ossSDK.MaxKeys(100),
		)
		if err != nil {
			return fmt.Errorf("列出文件夹内容失败: %w", err)
		}

		for _, obj := range resp.Objects {
			newKey := strings.Replace(obj.Key, oldFolder, newFolder, 1)
			if newKey == obj.Key {
				continue
			}
			if _, err := bucket.CopyObject(obj.Key, newKey); err != nil {
				return fmt.Errorf("复制对象 %s 失败: %w", obj.Key, err)
			}
			copiedObjects = append(copiedObjects, newKey)
			if err := bucket.DeleteObject(obj.Key); err != nil {
				return fmt.Errorf("删除原对象 %s 失败: %w", obj.Key, err)
			}
		}

		if !resp.IsTruncated {
			break
		}
		marker = resp.NextMarker
	}

	if err := bucket.DeleteObject(oldFolder); err != nil {
		return fmt.Errorf("删除原文件夹标记失败: %w", err)
	}
	return nil
}

func DeleteOSSFolder(bucket *ossSDK.Bucket, folderPath string) error {
	if folderPath == "" {
		return fmt.Errorf("文件夹路径不能为空")
	}
	folderPath = normalizeFolderPath(folderPath)

	marker := ""
	for {
		resp, err := bucket.ListObjects(
			ossSDK.Prefix(folderPath),
			ossSDK.Marker(marker),
			ossSDK.MaxKeys(100),
		)
		if err != nil {
			return fmt.Errorf("列出文件夹内容失败: %w", err)
		}

		var objectKeys []string
		for _, obj := range resp.Objects {
			objectKeys = append(objectKeys, obj.Key)
		}

		if len(objectKeys) > 0 {
			if err := deleteObjects(bucket, objectKeys); err != nil {
				return fmt.Errorf("批量删除对象失败: %w", err)
			}
		}

		if !resp.IsTruncated {
			break
		}
		marker = resp.NextMarker
	}
	return nil
}

func CreateOSSFolder(bucket *ossSDK.Bucket, folderPath string) error {
	folderPath = normalizeFolderPath(folderPath)
	return bucket.PutObject(folderPath, strings.NewReader(""))
}

func CheckOSSPathExists(bucket *ossSDK.Bucket, path string) (bool, error) {
	return bucket.IsObjectExist(path)
}

func SetOSSFolderACL(bucket *ossSDK.Bucket, folderPath string, isPublic bool) error {
	folderPath = normalizeFolderPath(folderPath)
	acl := ossSDK.ACLPrivate
	if isPublic {
		acl = ossSDK.ACLPublicRead
	}
	return bucket.SetObjectACL(folderPath, acl)
}

func DeleteObjects(bucket *ossSDK.Bucket, keys []string) error {
	if len(keys) == 0 {
		return nil
	}
	_, err := bucket.DeleteObjects(keys)
	return err
}

func RenameOSSObject(bucket *ossSDK.Bucket, oldKey, newKey string) error {
	if oldKey == "" || newKey == "" || oldKey == newKey {
		return nil
	}
	if _, err := bucket.CopyObject(oldKey, newKey); err != nil {
		return fmt.Errorf("复制失败: %w", err)
	}
	if err := bucket.DeleteObject(oldKey); err != nil {
		_ = bucket.DeleteObject(newKey)
		return fmt.Errorf("删除原文件失败: %w", err)
	}
	return nil
}

func SanitizeFileName(name string) string {
	sanitized := strings.Map(func(r rune) rune {
		if strings.ContainsRune(`/\:*?"<>|`, r) {
			return '_'
		}
		return r
	}, name)
	if sanitized == "" {
		sanitized = "untitled"
	}
	return sanitized
}

func deleteObjects(bucket *ossSDK.Bucket, objectKeys []string) error {
	if len(objectKeys) == 0 {
		return nil
	}
	_, err := bucket.DeleteObjects(objectKeys, ossSDK.DeleteObjectsQuiet(false))
	if err != nil {
		return fmt.Errorf("批量删除对象失败: %w", err)
	}
	return nil
}

func normalizeFolderPath(path string) string {
	if !strings.HasSuffix(path, "/") {
		return path + "/"
	}
	return path
}

// GetSTSCredentials 实现获取STS凭证的gRPC接口
func (s *OSSService) GetSTSCredentials(ctx context.Context, req *ossgrpc.GetSTSCredentialsRequest) (*ossgrpc.GetSTSCredentialsResponse, error) {
	// 创建STS客户端
	client, err := config.NewSTSClient()
	if err != nil {
		return &ossgrpc.GetSTSCredentialsResponse{
			Error: &ossgrpc.ErrorResponse{
				ErrorMsg: fmt.Sprintf("创建STS客户端失败: %v", err),
				Success:  false,
			},
		}, nil
	}

	// 构造请求
	request := sts.CreateAssumeRoleRequest()
	request.Scheme = "https"
	request.RoleArn = config.Aliyun.STSRoleARN
	request.RoleSessionName = fmt.Sprintf("user-%d", req.UserId)
	request.DurationSeconds = requests.NewInteger(int(req.Expiration))

	// 权限策略
	request.Policy = fmt.Sprintf(`{
		"Version": "1",
		"Statement": [{
			"Effect": "Allow",
			"Action": ["%s"],
			"Resource": ["%s"]
		}]
	}`, req.Action, req.Resource)

	// 获取凭证
	response, err := client.AssumeRole(request)
	if err != nil {
		return &ossgrpc.GetSTSCredentialsResponse{
			Error: &ossgrpc.ErrorResponse{
				ErrorMsg: fmt.Sprintf("获取STS凭证失败: %v", err),
				Success:  false,
			},
		}, nil
	}

	// 构造成功响应
	return &ossgrpc.GetSTSCredentialsResponse{
		Error: &ossgrpc.ErrorResponse{
			Success: true,
		},
		Credential: &ossgrpc.STSCredential{
			AccessKeyId:     response.Credentials.AccessKeyId,
			AccessKeySecret: response.Credentials.AccessKeySecret,
			SecurityToken:   response.Credentials.SecurityToken,
			Expiration:      response.Credentials.Expiration,
			Region:          config.Aliyun.Region,
			Bucket:          config.Aliyun.Bucket,
		},
	}, nil
}

// 实现 GetBucketInfo 方法
func (s *OSSService) GetBucketInfo(ctx context.Context, req *ossgrpc.GetBucketInfoRequest) (*ossgrpc.GetBucketInfoResponse, error) {
	// 从 oss-server 的配置中获取 Bucket 名称（config.Aliyun.Bucket 已在 oss-server 中初始化）
	bucketName := config.Aliyun.Bucket
	fmt.Println("swujiwijswiijxjiwxjsw", bucketName)

	if bucketName == "" {
		return &ossgrpc.GetBucketInfoResponse{
			Error: &ossgrpc.ErrorResponse{
				Success:  false,
				ErrorMsg: "oss-server 中未配置 Bucket 信息",
			},
		}, nil
	}

	// 返回成功响应，包含 Bucket 名称
	return &ossgrpc.GetBucketInfoResponse{
		Bucket: bucketName,
		Error: &ossgrpc.ErrorResponse{
			Success: true,
		},
	}, nil
}
